import matplotlib.pyplot as plt
import numpy as np
# 1. Grid Dimensions for the plot (Keep it small for a clean diagram)
N_time = 6 # Number of time steps (j)
M_price = 5 # Number of stock price steps (i)
# Create the figure
fig, ax = plt.subplots(figsize=(10, 6))
# 2. Draw the grid lines
for i in range(M_price + 1):
ax.axhline(y=i, color='lightgray', linestyle='--', zorder=1)
for j in range(N_time + 1):
ax.axvline(x=j, color='lightgray', linestyle='--', zorder=1)
# 3. Plot the nodes
for j in range(N_time + 1):
for i in range(M_price + 1):
# Condition 1: Expiration Payoff (The far right column)
if j == N_time:
ax.scatter(j, i, color='green', s=100, zorder=2, edgecolors='black', label='Known Expiration (Intrinsic Value)' if i==0 else "")
# Condition 2: Top Boundary (Max Stock Price)
elif i == M_price:
ax.scatter(j, i, color='blue', s=100, zorder=2, edgecolors='black', label='Known Top Boundary' if j==0 else "")
# Condition 3: Bottom Boundary (Zero Stock Price)
elif i == 0:
ax.scatter(j, i, color='purple', s=100, zorder=2, edgecolors='black', label='Known Bottom Boundary' if j==0 else "")
# Condition 4: Inner Nodes (The unknowns we are solving for)
else:
ax.scatter(j, i, color='white', s=100, zorder=2, edgecolors='black', label='Unknown Inner Nodes ($V_i^j$)' if i==1 and j==0 else "")
# 4. Add an arrow to show the direction of time-stepping
ax.annotate('', xy=(N_time - 1.5, M_price / 2), xytext=(N_time - 0.5, M_price / 2),
arrowprops=dict(facecolor='red', shrink=0.05, width=3, headwidth=10))
ax.text(N_time - 1, (M_price / 2) + 0.3, "Solving Backwards\nin Time",
color='red', ha='center', va='bottom', fontweight='bold')
# 5. Labels and Formatting
ax.set_title("Finite Difference Grid for Options Pricing", fontsize=16, fontweight='bold')
ax.set_xlabel("Time Steps ($j$) $\\longrightarrow$ \n (0 = Today, %d = Expiration T)" % N_time, fontsize=12)
ax.set_ylabel("Stock Price Steps ($i$) $\\uparrow$ \n (0 = \$0, %d = $S_{max})", fontsize=12, rotation=0, labelpad=88)
# Set ticks to match our grid indices
ax.set_xticks(np.arange(N_time + 1))
ax.set_yticks(np.arange(M_price + 1))
# Clean up axes limits so the dots aren't cut off
ax.set_xlim(-0.5, N_time + 0.5)
ax.set_ylim(-0.5, M_price + 0.5)
# Add a legend outside the plot
ax.legend(loc='upper left', bbox_to_anchor=(1.02, 1), borderaxespad=0.)
plt.tight_layout()
plt.show()